# This file is part of Indico.
# Copyright (C) 2002 - 2025 CERN
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see the
# LICENSE file for more details.

from flask import flash, request, session
from werkzeug.exceptions import Forbidden, NotFound

from indico.core.config import config
from indico.core.errors import NoReportError
from indico.legacy.pdfinterface.latex import AbstractsToPDF, generate_cached_pdf
from indico.modules.events.abstracts.controllers.base import RHAbstractBase, RHAbstractsBase
from indico.modules.events.abstracts.models.abstracts import AbstractState
from indico.modules.events.abstracts.operations import create_abstract, update_abstract
from indico.modules.events.abstracts.util import get_user_abstracts, make_abstract_form
from indico.modules.events.abstracts.views import WPDisplayAbstracts, WPDisplayCallForAbstracts
from indico.modules.events.util import get_field_values
from indico.util.i18n import _
from indico.web.flask.util import send_file, url_for
from indico.web.forms.base import FormDefaults
from indico.web.util import jsonify_data, jsonify_form, jsonify_template


class RHCallForAbstracts(RHAbstractsBase):
    """Show the main CFA page."""

    def _process(self):
        abstracts = get_user_abstracts(self.event, session.user) if session.user else []
        return WPDisplayCallForAbstracts.render_template('display/call_for_abstracts.html', self.event,
                                                         abstracts=abstracts)


class RHMyAbstractsExportPDF(RHAbstractsBase):
    """Export the list of the user's abstracts as PDF."""

    def _check_access(self):
        if not session.user:
            raise Forbidden
        RHAbstractsBase._check_access(self)

    def _process(self):
        if not config.LATEX_ENABLED:
            raise NotFound
        abstracts = get_user_abstracts(self.event, session.user)
        data = generate_cached_pdf(
            lambda: AbstractsToPDF(self.event, abstracts).generate(as_bytes=True),
            ('my-abstracts', '-'.join(sorted(str(a.id) for a in abstracts))),
        )
        return send_file('my-abstracts.pdf', data, 'application/pdf')


class RHSubmitAbstract(RHAbstractsBase):
    """Submit a new abstract."""

    ALLOW_LOCKED = True

    def _check_access(self):
        cfa = self.event.cfa
        if session.user and not cfa.is_open and not cfa.can_submit_abstracts(session.user):
            raise NoReportError.wrap_exc(Forbidden(_('The Call for Abstracts is closed. '
                                                     'Please contact the event organizer for further assistance.')))
        elif not session.user or not cfa.can_submit_abstracts(session.user):
            raise Forbidden
        RHAbstractsBase._check_access(self)

    def _process(self):
        abstract_form_class = make_abstract_form(self.event, session.user, management=self.management)
        form = abstract_form_class(event=self.event)
        if form.validate_on_submit():
            abstract, notifications_sent = create_abstract(self.event, *get_field_values(form.data),
                                                           send_notifications=True)
            if notifications_sent:
                flash(_("Your abstract '{}' has been successfully submitted. It is registered with the number "
                        '#{}. You will be notified by email with the submission details.')
                      .format(abstract.title, abstract.friendly_id), 'success')
            else:
                flash(_("Your abstract '{}' has been successfully submitted. It is registered with the number #{}.")
                      .format(abstract.title, abstract.friendly_id), 'success')
            return jsonify_data(flash=False, redirect=url_for('.call_for_abstracts', self.event))
        return jsonify_template('events/abstracts/display/submission.html', event=self.event, form=form)


class RHSubmitInvitedAbstract(RHAbstractBase):
    USE_ABSTRACT_UUID = True

    def _check_access(self):
        RHAbstractBase._check_access(self)
        if self.abstract.state != AbstractState.invited:
            raise Forbidden

    def _check_abstract_protection(self):
        token = request.view_args['uuid']
        return self.abstract.uuid == token

    def _create_form(self):
        form_user = session.user or self.abstract.submitter
        abstract_form_cls = make_abstract_form(self.event, form_user)
        custom_field_values = {f'custom_{x.contribution_field_id}': x.data for x in self.abstract.field_values}
        form_defaults = FormDefaults(self.abstract, **custom_field_values)
        return abstract_form_cls(obj=form_defaults, event=self.event, abstract=self.abstract)

    def _process_GET(self):
        return WPDisplayAbstracts.render_template('invited_abstract.html', self.abstract.event, abstract=self.abstract,
                                                  form=self._create_form())

    def _process_POST(self):
        form = self._create_form()
        if form.validate_on_submit():
            fields, custom_fields = get_field_values(form.data)
            abstract_data = dict(fields, state=AbstractState.submitted, uuid=None)
            update_abstract(self.abstract, abstract_data, custom_fields)
            return jsonify_data(flash=False, redirect=url_for('.call_for_abstracts', self.event))
        return jsonify_form(form, form_header_kwargs={'action': url_for('.submit_invited_abstract',
                                                                        self.abstract.locator.token)})
